package com.lorentzos.flingswipe;

import ohos.agp.components.*;
import ohos.agp.database.DataSetSubscriber;
import ohos.agp.render.Canvas;
import ohos.agp.utils.Point;
import ohos.app.Context;

/**
 * Created by dionysis_lorentzos on 5/8/14
 * for package com.lorentzos.swipecards
 * and project Swipe cards.
 * Use with caution dinosaurs might appear!
 */
public class SwipeFlingAdapterView extends BaseFlingAdapterView {
    private int MIN_ADAPTER_STACK = DEFAULT_MAX_VISIBLE;
    private float ROTATION_DEGREES = 15.f;

    private BaseItemProvider mAdapter;
    private int LAST_OBJECT_IN_STACK = 0;
    private onFlingListener mFlingListener;
    private AdapterDataSetObserver mDataSetObserver;
    private boolean mInLayout = false;
    private Component mActiveCard = null;
    private OnItemClickListener mOnItemClickListener;
    private FlingCardListener flingCardListener;
    private Point mLastTouchPoint;

    public SwipeFlingAdapterView(Context context) {
        this(context, null);
    }

    public SwipeFlingAdapterView(Context context, AttrSet attrSet) {
        this(context, attrSet, null);
    }

    public SwipeFlingAdapterView(Context context, AttrSet attrSet, String styleName) {
        super(context, attrSet, styleName);
    }

    /**
     * A shortcut method to set both the listeners and the adapter.
     *
     * @param context The activity context which extends onFlingListener, OnItemClickListener or both
     * @param mAdapter The adapter you have to set.
     */
    public void init(final Context context, BaseItemProvider mAdapter) {
        if (context instanceof onFlingListener) {
            mFlingListener = (onFlingListener) context;
        } else {
            throw new RuntimeException("ability does not implement SwipeFlingAdapterView.onFlingListener");
        }
        if (context instanceof OnItemClickListener) {
            mOnItemClickListener = (OnItemClickListener) context;
        }
        setItemProvider(mAdapter);
    }

    @Override
    public Component getSelectedComponent() {
        return mActiveCard;
    }

    @Override
    public void postLayout() {
        if (!mInLayout) {
            super.postLayout();
        }
    }

    @Override
    public void onRefreshed(Component component) {
        // if we don't have an adapter, we don't need to do anything
        if (mAdapter == null) {
            return;
        }
        mInLayout = true;
        Component topCard = getComponentAt(LAST_OBJECT_IN_STACK);
        if (mActiveCard != null && topCard != null && topCard == mActiveCard) {
            if (this.flingCardListener.isTouching()) {
                Point lastPoint = this.flingCardListener.getLastPoint();
                if (this.mLastTouchPoint == null || !this.mLastTouchPoint.equals(lastPoint)) {
                    this.mLastTouchPoint = lastPoint;
                    removeComponents(0, LAST_OBJECT_IN_STACK);
                }
            }
        } else {
            setTopView();
        }
        mInLayout = false;
    }

    @Override
    public void onDraw(Component component, Canvas canvas) {
        final int adapterCount = mAdapter.getCount();
        if (adapterCount <= MIN_ADAPTER_STACK) {
            mFlingListener.onAdapterAboutToEmpty(adapterCount);
        }
    }

    /**
     * Set the top view and add the fling listener
     */
    private void setTopView() {
        if (getChildCount() > 0) {
            mActiveCard = getComponentAt(LAST_OBJECT_IN_STACK);
            if (mActiveCard != null) {
                flingCardListener =
                        new FlingCardListener(
                                this,
                                mActiveCard,
                                mAdapter.getItem(0),
                                ROTATION_DEGREES,
                                new FlingCardListener.FlingListener() {
                                    @Override
                                    public void onCardExited() {
                                        mActiveCard = null;
                                        mFlingListener.removeFirstObjectInAdapter();
                                    }

                                    @Override
                                    public void leftExit(Object dataObject) {
                                        mFlingListener.onLeftCardExit(dataObject);
                                    }

                                    @Override
                                    public void rightExit(Object dataObject) {
                                        mFlingListener.onRightCardExit(dataObject);
                                    }

                                    @Override
                                    public void onClick(Object dataObject) {
                                        if (mOnItemClickListener != null) {
                                            mOnItemClickListener.onItemClicked(0, dataObject);
                                        }
                                    }

                                    @Override
                                    public void onScroll(float scrollProgressPercent) {
                                        mFlingListener.onScroll(scrollProgressPercent);
                                    }
                                });
                mActiveCard.setTouchEventListener(flingCardListener);
            }
        }
    }

    public FlingCardListener getTopCardListener() throws NullPointerException {
        if (flingCardListener == null) {
            throw new NullPointerException();
        }
        return flingCardListener;
    }

    public void setMinStackInAdapter(int MIN_ADAPTER_STACK) {
        this.MIN_ADAPTER_STACK = MIN_ADAPTER_STACK;
    }

    @Override
    public BaseItemProvider getItemProvider() {
        return mAdapter;
    }

    @Override
    public void setItemProvider(BaseItemProvider provider) {
        if (mAdapter != null && mDataSetObserver != null) {
            mAdapter.removeDataSubscriber(mDataSetObserver);
            mDataSetObserver = null;
        }
        mAdapter = provider;
        if (mAdapter != null && mDataSetObserver == null) {
            mDataSetObserver = new AdapterDataSetObserver();
            mAdapter.addDataSubscriber(mDataSetObserver);
        }
        super.setItemProvider(provider);
    }

    public void setFlingListener(onFlingListener onFlingListener) {
        this.mFlingListener = onFlingListener;
    }

    public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
        this.mOnItemClickListener = onItemClickListener;
    }

    @Override
    public LayoutConfig createLayoutConfig(Context context, AttrSet attrSet) {
        return new StackLayout.LayoutConfig(context, attrSet);
    }

    /**
     * The observer
     */
    private class AdapterDataSetObserver extends DataSetSubscriber {
        @Override
        public void onChanged() {
            postLayout();
        }

        @Override
        public void onInvalidated() {
            postLayout();
        }
    }

    public interface OnItemClickListener {
        void onItemClicked(int itemPosition, Object dataObject);
    }

    public interface onFlingListener {
        void removeFirstObjectInAdapter();

        void onLeftCardExit(Object dataObject);

        void onRightCardExit(Object dataObject);

        void onAdapterAboutToEmpty(int itemsInAdapter);

        void onScroll(float scrollProgressPercent);
    }
}
